package com.me.myFramework.myAop.aop200;

import com.me.myFramework.myAop.aop200.advice.Advice;
import com.me.myFramework.myAop.aop200.advice.method.AfterReturningAdvice;
import com.me.myFramework.myAop.aop200.advice.method.MethodBeforeAdvice;
import com.me.myFramework.myAop.aop200.intercept.method.AfterReturningAdviceInterceptor2;
import com.me.myFramework.myAop.aop200.intercept.method.MethodBeforeAdviceInterceptor;
import com.me.myFramework.myAop.aop200.intercept.method.MethodInterceptor;
import org.springframework.aop.Pointcut;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * 改进 AOP-130：代理套代理实现的多切面 优化为 单个代理实现多切面
 */
public class ProxyFactory {

    private Object target;

    private List<PointcutAdvisor> advisors = new ArrayList<>();

    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 动态代理织入增强逻辑，逻辑同 {@link org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader) JdkDynamicAopProxy#getProxy}
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                List<MethodInterceptor> interceptors = getInterceptors(method, target.getClass());
                int index = 0;

                // return interceptor.invoke(method, args, target);
                if (index < interceptors.size() - 1) {
                    return interceptors.get(index).invoke111(method, args, target, interceptors, index);
                }
                else {
                    return method.invoke(target, args);
                }
            }
        });
    }

    /**
     * 筛选出当前正在执行的方法适用的 advice（增强），并转换成 拦截器（执行增强逻辑的执行器）。
     * 逻辑类似 {@link org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice(java.lang.reflect.Method, java.lang.Class) AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice}
     *
     * @param method        正在执行的方法
     * @param targetClass   目标类
     *
     * @return  匹配当前方法的拦截器
     */
    private List<MethodInterceptor> getInterceptors(Method method, Class<?> targetClass) {
        List<MethodInterceptor> interceptorList = new ArrayList<>(this.advisors.size());
        for (PointcutAdvisor advisor : advisors) {
            Pointcut pointcut = advisor.getPointcut();
            if (pointcut.getClassFilter().matches(targetClass) && pointcut.getMethodMatcher().matches(method, targetClass)) {
                Advice advice = advisor.getAdvice();
                if (advice instanceof MethodBeforeAdvice) {
                    interceptorList.add(new MethodBeforeAdviceInterceptor((MethodBeforeAdvice) advice));
                }
                else if (advice instanceof AfterReturningAdvice) {
                    interceptorList.add(new AfterReturningAdviceInterceptor2((AfterReturningAdvice) advice));
                }
                else {
                    throw new RuntimeException("未知的 advice 类型");
                }
            }
        }

        return interceptorList;
    }

    public Object getTarget() {
        return target;
    }

    public void addAdvisor(PointcutAdvisor advisor) {
        this.advisors.add(advisor);
    }

    public List<PointcutAdvisor> getAdvisors() {
        return advisors;
    }

    public void setAdvisors(List<PointcutAdvisor> advisors) {
        this.advisors = advisors;
    }
}
